#include "Render.h"
#include "ui/uis/Object3DInfoGui.h"

static Render* staticRender;

Render::Render() : windowTitle(WINDOW_TITLE), windowWidth(WINDOW_WIDTH), windowHeight(WINDOW_HEIGHT){

}

/**
 * 获得实例
 * @return
 */
Render& Render::getRenderInstance() {
    if(nullptr == staticRender){
        staticRender = new Render();
    }
    HelloAssert::checkPtr(staticRender);
    return *staticRender;
}

/**
 * 初始化
 */
void Render::init() {

    //创建窗口
    createWindow();

    //编译所有Shader
    ShaderName shader1("test", "glsl/test.vs", "glsl/test.fs");
    ShaderUtil::setShaders({shader1});

    //创建待渲染的几何体
    renderLists();

    //初始化
    for (Geometry *item: rootGemetry) {
        item->init();
    }

    //初始化GUI
    initImGUI();

    //准备渲染
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
}

/**
 * 创建窗口
 */
void Render::createWindow() {
    //初始化GLFW
    if (!glfwInit()) {
        log_error("GLFW初始化失败");
        return;
    }
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, GL_MAJORVERSION);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, GL_MINORVERSION);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, NULL, NULL);
    if (nullptr == window) {
        log_error("create window was failed!");
        return;
    }
    glfwMakeContextCurrent(window);

    //将指针交给GLAD管理
    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
        log_error("GLAD指针管理初始化失败");
        return;
    }

    //初始化视口和绑定窗口大小发生改变时监听
    framebuff_size_callback(window, windowWidth, windowHeight);
    glfwSetFramebufferSizeCallback(window, framebuff_size_callback);
    glfwSetKeyCallback(window, key_callback);
    //glfwSetMouseButtonCallback();
}

/**
 * 主循环
 */
void Render::renderLoop() {
    while (!glfwWindowShouldClose(window)) {
        //事件处理
        processInputs();

        //初始化
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        //绘制场景
        render();

        //绘制GUI
        renderImGUI(rootGemetry[0]);

        //交换缓存
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    terminate();
}

/**
 * 绘制场景
 */
void Render::render() {
    Matrix4x4 proj;
    //Matrix4x4 proj = Matrix4x4::orthographic(-10, 10, -10, 10, 10, -1);
    //Matrix4x4 proj = Matrix4x4::perspective(Angle::deg2rad(45.0f), (float) windowWidth / (float) windowHeight, 0.1f, 100.0f);

//        Vector3 cameraPos(cameraPosData);
//        Vector3 cameraTarget(cameraTargetData);
//        Vector3 cameraUp(cameraUpData);
//        Matrix4x4 cameraMatrix = Matrix4x4::lookAt(cameraPos, cameraTarget, cameraUp);
//        Matrix4x4 view = Matrix4x4::inverse(cameraMatrix);
    Matrix4x4 view;

    for (Geometry *actor: rootGemetry) {
        Matrix4x4 model = actor->getModelmatrix();
        //model 变换
        //Matrix4x4 mvp = model * view * proj;
        actor->getShader().setUniform("u_mvp", model);
        actor->getShader().setUniform("u_view", view);
        actor->getShader().setUniform("u_model", model);
        actor->draw();
    }
}

/**
 * 屏幕缓冲区回调
 * @param window 上下文
 * @param width 宽
 * @param height 高
 */
void framebuff_size_callback(GLFWwindow *window, int width, int height) {
    log_info("window size callback, w=%d, h=%d", width, height);
    glViewport(0, 0, width, height);
}

/**
 * 按键回调
 * @param window 上下文
 * @param key 按键code
 * @param scancode scancode
 * @param action 动作，按下/抬起
 * @param mods 模式
 */
void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) {
    log_error("key_callback, key=%d, scancode=%d, action=%d,mods=%d", key, scancode, action, mods);
}

/**
 * 输入处理
 */
void Render::processInputs() {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, true);
    }

    if(glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS){
        log_info("检测到w按下事件");
    }

    double cx, cy;
    glfwGetCursorPos(window, &cx, &cy);
    //Log::info("x=%.3f, y=%.3f", cx, cy);
}


void Render::initImGUI() {
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGui::StyleColorsDark();
    ImGui_ImplGlfw_InitForOpenGL(window, true);
    ImGui_ImplOpenGL3_Init("#version 330");
    ImGuiIO &io = ImGui::GetIO();
    (void) io;
    io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\consola.ttf", 13.0f, NULL, io.Fonts->GetGlyphRangesChineseFull());
    io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\simhei.ttf", 15.0f, NULL, io.Fonts->GetGlyphRangesChineseFull());
}

void Render::renderImGUI(Geometry * geometry) {
    // Start the Dear ImGui frame
    ImGui_ImplOpenGL3_NewFrame();
    ImGui_ImplGlfw_NewFrame();
    ImGui::NewFrame();

    if (showDemoGUI) {
        ImGui::ShowDemoWindow(&showDemoGUI);
    }

    if (showMyGUI) {
        Object3DInfoGui object3DInfoGui;
        object3DInfoGui.render(geometry);
    }

    ImGui::Render();
    ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}

void Render::renderLists() {
//    Geometry *cube = new Cube(1.0f);
//    Geometry * cube2 = new Cube(0.5f);
//    Geometry * cube3 = new Cube(2.0f);
//    rootGemetry.push_back(cube);
//    rootGemetry.push_back(cube2);
//    rootGemetry.push_back(cube3);

//    Geometry *tri = new Triangle(Vector3(0.0f, 0.5f, 0.0f), Vector3(-0.5f, -0.5f, 0.0f), Vector3(0.5f, -0.5f, 0.0f));
//    //tri->setDrawMode(DrawMode::M_LINE_LOOP);
//    tri->setShaderName("test");
//    tri->setTranslate(Vector3(0, 0.6f, -4.0));
//    tri->setRotator(Vector3(0, 0, 0));
//    tri->setScale(Vector3(1.0, 1.0, 1.0));
//    rootGemetry.push_back(tri);
//

    Geometry *cube = new Cube(0.1f);
    //cube->setShaderName("test");
    //cube->setDrawMode(DrawMode::M_LINE_LOOP);
    //cube->setTranslate(Vector3(0.0f, 0.0f, -1.0f));
    rootGemetry.push_back(cube);

    Geometry *axies = new Axies(0.3f);
    cube->children.push_back(axies);
}

/**
 * 结束
 */
void Render::terminate() {
    log_info("关闭");
    //4.关闭
    glfwTerminate();
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();
    delete staticRender;
}






